package tresp.bthreads;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;

import robocode.ScannedRobotEvent;
import tresp.coordinator.ICoordinator;
import tresp.utils.BThreadVote;
import tresp.utils.ITankInfo;
import tresp.utils.logging.MyLogger;


/**
 * <b>EncloseEnemyMove</b>
 * 
 * 
 * @author <font color="blue">Maxim Kirilov</font>
 *
 */
public class EncloseEnemyMove extends BThread {

    private static Logger logger = MyLogger.getLogger( EncloseEnemyMove.class );
    
    private ITankInfo tankInfo;
    
    private AtomicReference<ScannedRobotEvent> lastScannedRobotEvent;
    

    private double circleDir = 1.0D;
    private double enemyFirePower;
    private double enemyEnergy;
    
    
    
    public EncloseEnemyMove(ICoordinator<BThreadVote> coordinator) {
	super(coordinator);
	tankInfo = coordinator.getTankInfo();
	lastScannedRobotEvent = new AtomicReference<ScannedRobotEvent>();
	logger.info("EncloseEnemyMove B-Thread created successfully");
    }

    @Override
    public void vote() {
	
	ScannedRobotEvent e = lastScannedRobotEvent.getAndSet( null );
	if ( e!= null){
	    List<BThreadVote> lRec = buildMovePattern( e );

	    int votesCount = lRec.size();
	    for (BThreadVote vote : lRec){
		vote.setWeight( weight + (votesCount--) );
		coordinator.vote( vote );	
	    }
	}
    }

    
    @Override
    public void onScannedRobot(ScannedRobotEvent e){
	lastScannedRobotEvent.set( e );
    }

    private List<BThreadVote> buildMovePattern(ScannedRobotEvent e) {
	Point2D.Double robotLocation = new Point2D.Double(tankInfo.getX(), tankInfo.getY());

	double enemyAbsoluteBearing = tankInfo.getHeadingRadians() + e.getBearingRadians();
	double enemyDistance = e.getDistance();

	if (((enemyEnergy = enemyEnergy - e.getEnergy()) >= 0.1D) && (enemyEnergy <= 3.0D)) {
	    enemyFirePower = enemyEnergy;
	}

	enemyEnergy = e.getEnergy();

	Rectangle2D.Double BF = new Rectangle2D.Double(18.0D, 18.0D, 764.0D, 564.0D);

	double distDelta = 1.590796326794897D + (enemyDistance > 525.0D ? -0.1D : 0.5D);
	Point2D.Double newDestination;
	while (!BF.contains(newDestination = projectMotion(robotLocation, 
		enemyAbsoluteBearing + circleDir * (distDelta -= 0.02D), 170.0D)));
	double theta = 0.5952D * (20.0D - 3.0D * enemyFirePower) / enemyDistance;
	if ((Math.random() > Math.pow(theta, theta)) || 
		(distDelta < 0.6283185307179586D) || 
		((distDelta < 0.8975979010256552D) && (enemyDistance < 400.0D))) {
	    circleDir = -circleDir;
	}

	theta = absoluteBearing(robotLocation, newDestination) - tankInfo.getHeadingRadians();
	
	BThreadVote vote;
	List<BThreadVote> lRecommendations = new ArrayList<BThreadVote>();
	
	vote = new BThreadVote(BThreadType.MOVE_AHEAD, 0D, Math.cos(theta) * 100.0D);
	lRecommendations.add( vote );
	
	vote = new BThreadVote(BThreadType.TURN_RIGHT_RADIANS, 0D, Math.tan(theta));
	lRecommendations.add( vote );
	
	return lRecommendations;
    }
    
    private Point2D.Double projectMotion(Point2D.Double loc, double heading, double distance) {
	return new Point2D.Double(loc.x + distance * Math.sin(heading), loc.y + distance * Math.cos(heading));
    }

    private double absoluteBearing(Point2D.Double source, Point2D.Double target) {
	return Math.atan2(target.x - source.x, target.y - source.y);
    }

    @Override
    public String getName() {
	return "EncloseEnemyMove";
    }
}
